package com.lagou.edu.factory;

import com.lagou.edu.pojo.TestAutowired;
import com.lagou.edu.pojo.TestService;
import com.lagou.edu.pojo.TestTransactional;
import com.lagou.edu.utils.ClassUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
@TestService
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String,Object> map = new HashMap<>();  // 存储对象


    static {
        List<Class> classList;
        try {
            //扫描获取class文件
            classList = ClassUtils.getClassByPackagePath("com.lagou.edu");
            for (Class aClass : classList) {
                if(aClass.isInterface()){
                    continue;
                }
                String id = "";
                //解析TestService标签加入到容器
                TestService annotation = (TestService) aClass.getAnnotation(TestService.class);
                if(null == annotation || "".equals(annotation)){
                    continue;
                }
                String value = annotation.value();
                if(null == value ||"".equals(value)){
                    Class[] interfaces = aClass.getInterfaces();
                    if(interfaces.length > 0) {
                        id = interfaces[0].getSimpleName().substring(0,1).toLowerCase() + interfaces[0].getSimpleName().substring(1);
                    }else {
                        id = aClass.getSimpleName().substring(0,1).toLowerCase() + aClass.getSimpleName().substring(1);
                    }
                }else {
                    id = value;
                }
                Object o = aClass.newInstance();  // 实例化之后的对象
                map.put(id,o);
            }
            //解析TestAutowirded标签进行注入
            for (String key: map.keySet()) {
                Object value = map.get(key);
                Class<?> aClass = value.getClass();
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    declaredField.setAccessible(true);
                    TestAutowired annotation = declaredField.getAnnotation(TestAutowired.class);
                    if(null != annotation) {
                        String name = declaredField.getType().getName();
                        name = name.substring(name.lastIndexOf(".") + 1);
                        name = name.substring(0,1).toLowerCase() + name.substring(1);
                        Object o = map.get(name);
                        declaredField.set(value,o);
                    }
                }
            }
            //解析@Transactional标签根据是否是接口进行动态代理，替换原来生成的bean
            for (String key: map.keySet()) {
                Object value = map.get(key);
                Class<?> aClass = value.getClass();
                TestTransactional annotation = aClass.getAnnotation(TestTransactional.class);
                if(null == annotation || "".equals(annotation)){
                    continue;
                }
                ProxyFactory proxyFactory = (ProxyFactory) map.get("proxyFactory");
                Class<?>[] interfaces = aClass.getInterfaces();
                if(interfaces.length > 0){
                    Object jdkProxy = proxyFactory.getJdkProxy(value);
                    map.put(key,jdkProxy);
                }else{
                    Object cglibProxy = proxyFactory.getCglibProxy(value);
                    map.put(key,cglibProxy);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
